001    /**
002     * Java Gui Builder - A library to build GUIs using an XML file.
003     * Copyright 2002, 2003 (C) François Beausoleil
004     *
005     * This library is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU Lesser General Public
007     * License as published by the Free Software Foundation; either
008     * version 2.1 of the License, or (at your option) any later version.
009     *
010     * This library is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013     * Lesser General Public License for more details.
014     *
015     * You should have received a copy of the GNU Lesser General Public
016     * License along with this library; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018     */
019    
020    package jgb.handlers.swing;
021    
022    import jgb.builder.TagHandler;
023    import jgb.builder.utils.CurrentObjectsStackManager;
024    import org.xml.sax.Locator;
025    import org.xml.sax.SAXException;
026    import org.xml.sax.SAXParseException;
027    
028    import java.awt.*;
029    import java.util.Map;
030    
031    
032    /**
033     * Default implementation for {@link jgb.builder.TagHandler TagHandler}.
034     * This default implementation does not allow subclasses to override
035     * {@link #startElement(java.lang.String, java.util.Map, java.util.Map) startElement(String, Map, Map)}
036     * or {@link #endElement(java.lang.String, java.util.Map) endElement(String, Map)}.  It provides equivalent
037     * methods in the form of {@link #enterElement(java.util.Map) enterElement(Map)}
038     * and {@link #exitElement() exitElement()}.<p>
039     * This class also provides many helpful methods:
040     * <ul>
041     * <li>
042     * {@link #getObject(java.lang.String) getObject(String)} and
043     * {@link #putObject(java.lang.String, java.lang.Object) putObject(String, Object)}<br />
044     * Return or update an object in the context based on the object's id. Uses
045     * the key {@link jgb.builder.TagHandler#OBJECTS_MAP_KEY TagHandler.OBJECTS_MAP_KEY}
046     * </li>
047     * <li>
048     * {@link #pushCurrentObject(java.lang.String, java.lang.Object) pushCurrentObject(String, Object)}
049     * and {@link #popCurrentObject() popCurrentObject()}<br />
050     * Push or pop the current object from the current objects stack.  Uses the key
051     * {@link jgb.builder.TagHandler#CURRENT_OBJECTS_STACK_KEY TagHandler.CURRENT_OBJECTS_STACK_KEY}
052     * </li>
053     * </ul>
054     * @see jgb.builder.utils.CurrentObjectsStackManager CurrentObjectsStackManager
055     * - Manage a stack of objects
056     * @since 0.1a
057     * @author Francois Beausoleil, <a href="mailto:fbos@users.sourceforge.net">fbos@users.sourceforge.net</a>
058     */
059    public abstract class AbstractTagHandler implements TagHandler {
060        /**
061         * The name of the id attribute.
062         */
063        protected static final String ATTR_ID = "id";
064    
065        /**
066         * The name of the class attribute.
067         */
068        protected static final String ATTR_CLASS = "class";
069    
070        /**
071         * The name of the refid attribute.
072         */
073        protected static final String ATTR_REFID = "refid";
074    
075        protected String tagName;
076        protected Map tagContext;
077    
078        public final void startElement(String qName, Map tagContext, Map atts) throws SAXException {
079            this.tagContext = tagContext;
080            this.tagName = qName;
081    
082            try {
083                enterElement(atts);
084            } catch (SAXException e) {
085                throw e;
086            } catch (Exception e) {
087                e.printStackTrace();
088                throwParsingException("Unhandled exception while entering element" + qName, e);
089            } finally {
090                this.tagContext = null;
091                this.tagName = null;
092            }
093        }
094    
095        public final void endElement(String qName, Map tagContext) throws SAXException {
096            this.tagContext = tagContext;
097            this.tagName = qName;
098    
099            try {
100                exitElement();
101            } catch (SAXException e) {
102                throw e;
103            } catch (Exception e) {
104                throwParsingException("Unhandled exception while exiting element " + qName, e);
105            } finally {
106                this.tagContext = null;
107                this.tagName = null;
108            }
109        }
110    
111        protected Object getObject(String id) {
112            Map objectsMap = (Map)tagContext.get(TagHandler.OBJECTS_MAP_KEY);
113            return objectsMap.get(id);
114        }
115    
116        protected void putComponent(String id, Component component) {
117            putObject(id, component);
118        }
119    
120        protected void putObject(String id, Object value) {
121            Map objectsMap = (Map)tagContext.get(TagHandler.OBJECTS_MAP_KEY);
122            objectsMap.put(id, value);
123        }
124    
125        protected void pushCurrentObject(Object o) {
126            pushCurrentObject(null, o);
127        }
128    
129        /**
130         * Pushes the passed object and id to the current objects stack.
131         */
132        protected void pushCurrentObject(String id, Object o) {
133            getCurrentObjectsStack().pushCurrentObject(o, id);
134            updateCurrentObject();
135        }
136    
137        protected void popCurrentObject() {
138            getCurrentObjectsStack().popCurrentObject();
139            updateCurrentObject();
140        }
141    
142        protected Object getCurrentObject() {
143            return getCurrentObjectsStack().getCurrentObject();
144        }
145    
146        protected String getCurrentObjectId() {
147            return getCurrentObjectsStack().getCurrentObjectId();
148        }
149    
150        protected boolean isCurrentObjectValid() {
151            return getCurrentObjectsStack().isCurrentObjectValid();
152        }
153    
154        protected void throwParsingException(String msg) throws SAXException {
155            throwParsingException(msg, null);
156        }
157    
158        protected void throwParsingException(Exception cause) throws SAXException {
159            throwParsingException(null, cause);
160        }
161    
162        /**
163         * Throw a {@link org.xml.sax.SAXException} or a subclass if a locator is
164         * available.
165         */
166        protected void throwParsingException(String msg, Exception cause) throws SAXException {
167            Locator locator = (Locator)tagContext.get(TagHandler.DOCUMENT_LOCATOR_KEY);
168            if (locator == null) {
169                throw new SAXException(msg + " tag " + tagName, cause);
170            } else {
171                throw new SAXParseException(msg + " tag " + tagName, locator, cause);
172            }
173        }
174    
175        /**
176         * Actually handle the element's behaviour when the element's start
177         * is encountered.
178         */
179        protected abstract void enterElement(Map atts) throws SAXException;
180    
181        /**
182         * Actually handle the element's behaviour when the element's closure
183         * is encountered.
184         */
185        protected abstract void exitElement() throws SAXException;
186    
187        private CurrentObjectsStackManager getCurrentObjectsStack() {
188            CurrentObjectsStackManager stackManager =
189                    (CurrentObjectsStackManager)tagContext.get(TagHandler.CURRENT_OBJECTS_STACK_KEY);
190            if (stackManager == null) {
191                stackManager = new CurrentObjectsStackManager();
192                tagContext.put(TagHandler.CURRENT_OBJECTS_STACK_KEY, stackManager);
193            }
194    
195            return stackManager;
196        }
197    
198        private void updateCurrentObject() {
199            tagContext.remove(TagHandler.CURRENT_OBJECT_KEY);
200            tagContext.remove(TagHandler.CURRENT_OBJECT_ID_KEY);
201    
202            if (isCurrentObjectValid()) {
203                tagContext.put(TagHandler.CURRENT_OBJECT_KEY, getCurrentObject());
204                String objectId = getCurrentObjectId();
205                if (objectId != null) {
206                    tagContext.put(TagHandler.CURRENT_OBJECT_ID_KEY, objectId);
207                }
208            }
209        }
210    }